using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;
using Matrix.ServiceDiscovery.Dtos;

namespace Matrix.ServiceDiscovery.Services
{
    /// <summary>
    /// 服务发现缓存服务
    /// 实现L1本地缓存 + L2分布式缓存的多级缓存策略
    /// </summary>
    public class ServiceDiscoveryCacheService : ITransientDependency
    {
        private readonly IMemoryCache _localCache;
        private readonly IDistributedCache _distributedCache;
        private readonly ILogger<ServiceDiscoveryCacheService> _logger;

        // 缓存键前缀
        private const string CACHE_PREFIX = "Matrix:ServiceDiscovery:";

        // 默认缓存过期时间
        private static readonly TimeSpan DEFAULT_EXPIRATION = TimeSpan.FromMinutes(30);
        private static readonly TimeSpan SHORT_EXPIRATION = TimeSpan.FromMinutes(5);
        private static readonly TimeSpan LONG_EXPIRATION = TimeSpan.FromHours(2);

        public ServiceDiscoveryCacheService(
            IMemoryCache localCache,
            IDistributedCache distributedCache,
            ILogger<ServiceDiscoveryCacheService> logger)
        {
            _localCache = localCache;
            _distributedCache = distributedCache;
            _logger = logger;
        }

        /// <summary>
        /// 智能缓存获取策略
        /// </summary>
        public async Task<T?> GetOrSetAsync<T>(
            string cacheKey,
            Func<Task<T>> factory,
            TimeSpan? absoluteExpiration = null,
            TimeSpan? slidingExpiration = null) where T : class
        {
            // 1. L1本地缓存查询（微秒级）
            if (_localCache.TryGetValue(cacheKey, out T? localValue))
            {
                _logger.LogDebug("L1缓存命中: {CacheKey}", cacheKey);
                return localValue;
            }

            // 2. L2分布式缓存查询（毫秒级）
            var distributedValue = await GetFromDistributedCacheAsync<T>(cacheKey);
            if (distributedValue != null)
            {
                // 回填L1缓存
                SetLocalCache(cacheKey, distributedValue, slidingExpiration ?? TimeSpan.FromMinutes(5));
                _logger.LogDebug("L2缓存命中，已回填L1缓存: {CacheKey}", cacheKey);
                return distributedValue;
            }

            // 3. 数据源查询并缓存
            var value = await factory();

            // 设置双重缓存
            await SetAsync(cacheKey, value, absoluteExpiration ?? DEFAULT_EXPIRATION, slidingExpiration);

            _logger.LogDebug("缓存未命中，已从数据源加载并缓存: {CacheKey}", cacheKey);
            return value;
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        public async Task SetAsync<T>(
            string cacheKey,
            T value,
            TimeSpan absoluteExpiration,
            TimeSpan? slidingExpiration = null) where T : class
        {
            // 设置L1缓存 - 短期高频访问
            SetLocalCache(cacheKey, value, slidingExpiration ?? TimeSpan.FromMinutes(5));

            // 设置L2缓存 - 长期持久化
            await SetDistributedCacheAsync(cacheKey, value, absoluteExpiration);
        }

        /// <summary>
        /// 移除缓存
        /// </summary>
        public async Task RemoveAsync(string cacheKey)
        {
            _localCache.Remove(cacheKey);
            await _distributedCache.RemoveAsync(cacheKey);

            _logger.LogDebug("移除缓存: {CacheKey}", cacheKey);
        }

        /// <summary>
        /// 按模式移除缓存
        /// </summary>
        public async Task RemoveByPatternAsync(string pattern)
        {
            // 获取所有匹配的缓存键
            var keysToRemove = GetCacheKeysByPattern(pattern);

            foreach (var key in keysToRemove)
            {
                await RemoveAsync(key);
            }

            _logger.LogInformation("按模式移除缓存: {Pattern}, 移除数量: {Count}", pattern, keysToRemove.Count);
        }

        /// <summary>
        /// 清理服务相关缓存
        /// </summary>
        public async Task InvalidateServiceCachesAsync(Guid serviceId, string serviceName)
        {
            var cacheKeys = new[]
            {
                GetServiceCacheKey(serviceId),
                GetByNameCacheKey(serviceName),
                GetInstancesCacheKey(serviceId),
                GetLoadBalancingConfigCacheKey(serviceId),
                GetHealthyInstancesCacheKey(serviceName)
            };

            await Task.WhenAll(cacheKeys.Select(RemoveAsync));

            // 清理列表缓存
            await RemoveByPatternAsync($"{CACHE_PREFIX}list:*");

            // 清理搜索缓存
            await RemoveByPatternAsync($"{CACHE_PREFIX}search:*");

            // 清理统计缓存
            await RemoveAsync(GetStatisticsCacheKey());

            _logger.LogInformation("清理服务相关缓存: {ServiceName} ({ServiceId})", serviceName, serviceId);
        }

        /// <summary>
        /// 清理实例相关缓存
        /// </summary>
        public async Task InvalidateInstanceCachesAsync(Guid serviceId, string serviceName, Guid instanceId)
        {
            var cacheKeys = new[]
            {
                GetInstancesCacheKey(serviceId),
                GetHealthyInstancesCacheKey(serviceName),
                GetHealthRecordsCacheKey(instanceId, null)
            };

            await Task.WhenAll(cacheKeys.Select(RemoveAsync));

            _logger.LogDebug("清理实例相关缓存: {ServiceName}/{InstanceId}", serviceName, instanceId);
        }

        #region Cache Key Generation Methods

        public static string GetServiceCacheKey(Guid id) => $"{CACHE_PREFIX}service:{id}";

        public static string GetByNameCacheKey(string serviceName) => $"{CACHE_PREFIX}by-name:{serviceName}";

        public static string GetListCacheKey(GetServiceListInput input)
        {
            var key = $"{CACHE_PREFIX}list:";
            key += $"type:{input.ServiceType ?? "all"}|";
            key += $"group:{input.ServiceGroup ?? "all"}|";
            key += $"status:{input.Status?.ToString() ?? "all"}|";
            key += $"keyword:{input.Keyword ?? ""}|";
            key += $"skip:{input.SkipCount}|take:{input.MaxResultCount}";

            return key;
        }

        public static string GetInstancesCacheKey(Guid serviceId) => $"{CACHE_PREFIX}instances:{serviceId}";

        public static string GetHealthyInstancesCacheKey(string serviceName) => $"{CACHE_PREFIX}healthy-instances:{serviceName}";

        public static string GetLoadBalancingConfigCacheKey(Guid serviceId) => $"{CACHE_PREFIX}lb-config:{serviceId}";

        public static string GetHealthRecordsCacheKey(Guid instanceId, GetHealthCheckRecordsInput? input)
        {
            var key = $"{CACHE_PREFIX}health-records:{instanceId}";
            if (input != null)
            {
                key += $":{input.StartTime:yyyyMMddHHmmss}-{input.EndTime:yyyyMMddHHmmss}";
                key += $":{input.SkipCount}-{input.MaxResultCount}";
            }
            return key;
        }

        public static string GetSearchCacheKey(SearchServicesInput input)
        {
            var key = $"{CACHE_PREFIX}search:";
            key += $"keyword:{input.Keyword ?? ""}|";
            key += $"types:{string.Join(",", input.ServiceTypes ?? new string[0])}|";
            key += $"statuses:{string.Join(",", input.Statuses?.Select(s => s.ToString()) ?? new string[0])}|";
            key += $"{input.SkipCount}-{input.MaxResultCount}";

            return key;
        }

        public static string GetStatisticsCacheKey() => $"{CACHE_PREFIX}statistics";

        #endregion

        #region Private Methods

        private async Task<T?> GetFromDistributedCacheAsync<T>(string cacheKey) where T : class
        {
            try
            {
                var cachedBytes = await _distributedCache.GetAsync(cacheKey);
                if (cachedBytes == null)
                {
                    return null;
                }

                var json = System.Text.Encoding.UTF8.GetString(cachedBytes);
                return JsonSerializer.Deserialize<T>(json);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "从分布式缓存获取数据失败: {CacheKey}", cacheKey);
                return null;
            }
        }

        private async Task SetDistributedCacheAsync<T>(string cacheKey, T value, TimeSpan expiration) where T : class
        {
            try
            {
                var json = JsonSerializer.Serialize(value);
                var bytes = System.Text.Encoding.UTF8.GetBytes(json);

                var options = new DistributedCacheEntryOptions
                {
                    AbsoluteExpirationRelativeToNow = expiration
                };

                await _distributedCache.SetAsync(cacheKey, bytes, options);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "设置分布式缓存失败: {CacheKey}", cacheKey);
            }
        }

        private void SetLocalCache<T>(string cacheKey, T value, TimeSpan slidingExpiration) where T : class
        {
            try
            {
                var options = new MemoryCacheEntryOptions
                {
                    SlidingExpiration = slidingExpiration
                };

                _localCache.Set(cacheKey, value, options);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "设置本地缓存失败: {CacheKey}", cacheKey);
            }
        }

        private List<string> GetCacheKeysByPattern(string pattern)
        {
            // 简单的模式匹配实现
            // 在实际项目中，可以使用更复杂的缓存键管理机制
            var keys = new List<string>();

            // 这里可以根据实际的缓存键存储机制来实现
            // 由于IMemoryCache不提供遍历所有键的方法，这里只是一个示例实现

            return keys;
        }

        #endregion
    }

    /// <summary>
    /// 缓存配置选项
    /// </summary>
    public class ServiceDiscoveryCacheOptions
    {
        /// <summary>
        /// L1本地缓存过期时间（滑动）
        /// </summary>
        public TimeSpan LocalCacheSlidingExpiration { get; set; } = TimeSpan.FromMinutes(5);

        /// <summary>
        /// L2分布式缓存默认过期时间
        /// </summary>
        public TimeSpan DistributedCacheDefaultExpiration { get; set; } = TimeSpan.FromMinutes(30);

        /// <summary>
        /// 短期缓存过期时间
        /// </summary>
        public TimeSpan ShortTermExpiration { get; set; } = TimeSpan.FromMinutes(5);

        /// <summary>
        /// 长期缓存过期时间
        /// </summary>
        public TimeSpan LongTermExpiration { get; set; } = TimeSpan.FromHours(2);

        /// <summary>
        /// 是否启用本地缓存
        /// </summary>
        public bool EnableLocalCache { get; set; } = true;

        /// <summary>
        /// 是否启用分布式缓存
        /// </summary>
        public bool EnableDistributedCache { get; set; } = true;
    }
}